package com.gcloud.service.common.lvm.uitls;

import java.io.File;

import com.gcloud.common.util.SystemUtil;
import com.gcloud.core.exception.GCloudException;

import lombok.extern.slf4j.Slf4j;
@Slf4j
public class LvmUtil {
	private static final String VG_PATH = "/cephFileSystem/vg/%s";//sharefiles  暂时先用cephFileSystem这个文件夹
	private static final long VG_LOCK_TIMEOUT = 200 * 1000L;
	private static final long CHECK_VG_TIMEOUT = 5 * 60 * 1000L;
	
	/**
	 * 创建lv
	 * @param vg
	 * @param lv
	 * @param size lv大小 ，单位G
	 * @return
	 */
	public static boolean lvCreate(String vg,String lv,int size, String errorCode){
		long lastTime = -1l;
		try {
			lastTime = lockVg(vg);
		
			String[] createLv = new String[]{"lvcreate", "-L", size + "G", "-n", lv, vg, "-Zn"};
			exec(createLv, errorCode);
		}catch (GCloudException e) {
			log.error("lvCreate error", e);
			return false;
		} finally {
			deleteVgSign(vg, lastTime);
		}
		
		return true;
	}
	
	/**
	 * dd拷贝
	 * @param infile 源文件路径
	 * @param vg vg名称
	 * @param lv lv名称
	 * @return
	 */
	public static void ddToVg(String infile,String vg,String lv, String errorCode){
		String[] ddCmd = new String[]{"dd", "if=" + infile, "of=/dev/" + vg + "/" + lv, "bs=5M"};
		try {
			exec(ddCmd, errorCode);
        } catch(GCloudException gex) {
        	clearImageData( vg, lv);
        	throw new GCloudException(errorCode);
        }
	}
	
	public static void clearImageData(String vg,String lv){
		long lastTime = -1l;
		try {
			lastTime = lockVg(vg);
			
			unActiveLv("/dev/" + vg + "/" + lv);
			String[] removeLv = new String[]{"lvremove", "-f", "/dev/" + vg + "/" + lv };
			exec(removeLv, "::清除镜像数据" + "/dev/" + vg + "/" + lv + "失败");
		}catch (GCloudException e) {
			log.error("clearImageData error", e);
		} finally {
			deleteVgSign(vg, lastTime);
		}
	}
	
	public static void remove(String vg,String lv){
		long lastTime = -1l;
		try {
			lastTime = lockVg(vg);
			
			unActiveLv("/dev/" + vg + "/" + lv);
			String[] removeLv = new String[]{"lvremove", "-f", "/dev/" + vg + "/" + lv };
			exec(removeLv, "::删除卷" + "/dev/" + vg + "/" + lv + "失败");
		}catch (GCloudException e) {
			log.error("lv remove error", e);
		} finally {
			deleteVgSign(vg, lastTime);
		}
	}
	
	/**后续需要针对lv做分布式同步锁
	 * @param lvPath
	 */
	public static void activeLv(String lvPath) {
		String imageLv = SystemUtil.run(new String[]{"bash","-c"," lvscan | grep "+ lvPath + "\\\'" });
    	//如果是inactive的，则激活
    	if(imageLv.toLowerCase().indexOf("inactive") != -1){
    		int activeLv = SystemUtil.runAndGetCode(new String[]{ "lvchange", "-ay", lvPath});
    		if (activeLv != 0){
                throw new GCloudException("::fail to active imageLv");
            }
    	}
	}
	
	/**后续需要针对lv做分布式同步锁
	 * @param lvPath
	 */
	public static void unActiveLv(String lvPath) {
		String imageLv = SystemUtil.run(new String[]{"bash","-c"," lvscan | grep "+ lvPath + "\\\'" });
    	//如果是inactive的，则激活
    	if(imageLv.toLowerCase().indexOf("active") != -1){
    		int unactiveLv = SystemUtil.runAndGetCode(new String[]{ "lvchange", "-an", lvPath});
    		if (unactiveLv != 0){
                throw new GCloudException("::fail to unactive imageLv");
            }
    	}
	}
	
	/**
	 * 扩展lv大小
	 * @param vg
	 * @param lv
	 * @param size 大小，单位G
	 * @return
	 */
	public static void extend(String vg,String lv,int size) {
		long lastTime = -1l;
		try {
			lastTime = lockVg(vg);
			
			activeLv("/dev/" + vg + "/" + lv);
			
			String[] extendLv = new String[]{"lvextend", "-L", "+" + size + "G" ,"/dev/" + vg + "/" + lv };
			exec(extendLv, "::扩展" + "/dev/" + vg + "/" + lv + "失败");
		}catch (GCloudException e) {
			log.error("lv extend error", e);
		} finally {
			deleteVgSign(vg, lastTime);
		}

	}
	
	/*public static void resize2fs(String vg,String lv) {
		String[] resizeLv = new String[]{"resize2fs", "-f", "/dev/" + vg + "/" + lv ,"-f"};
		exec(resizeLv, "::resize" + "/dev/" + vg + "/" + lv + "文件系统失败");
	}*/
	
	public static void snap(String vg,String lv,String snapshotName) {
		long lastTime = -1l;
		try {
			lastTime = lockVg(vg);
			
			//lvcreate -s -l 100 -n volumeNameSnap /dev/poolName/volumeName
			String[] snapLv = new String[]{"lvcreate", "-s", "-l" , "100" , "-n", snapshotName, "/dev/" + vg + "/" + lv };
			exec(snapLv, "::快照" + "/dev/" + vg + "/" + lv + "失败");
		}catch (GCloudException e) {
			log.error("lv snapshot error", e);
		} finally {
			deleteVgSign(vg, lastTime);
		}
	}
	
	/**快照恢复
	 * @param vg
	 * @param snapLvName
	 */
	public static void convert(String vg,String snapLvName) {
		long lastTime = -1l;
		try {
			lastTime = lockVg(vg);
			
			String[] snapLv = new String[]{"lvconvert", "--merge", "/dev/" + vg + "/" + snapLvName };
			exec(snapLv, "::快照" + "/dev/" + vg + "/" + snapLvName + "恢复失败");
		}catch (GCloudException e) {
			log.error("snapshot convert error", e);
		} finally {
			deleteVgSign(vg, lastTime);
		}
	}
	
	public static String getVolumePath(String poolName,String volumeId) {
		return String.format("/dev/%s/volume-%s", poolName, volumeId);
	}
	
	public static String getImagePath(String poolName,String imageId) {
		return String.format("/dev/%s/img-%s", poolName, imageId);
	}
	
	public static void exec(String[] cmd, String errorCode) {
		int res = SystemUtil.runAndGetCode(cmd);
		if(res != 0) {
			throw new GCloudException(errorCode);
		}
	}
	
	private static long createVgSign(String vg) {
		int res = SystemUtil.runAndGetCode(new String[]{"mkdir", getVgSignPath(vg)});
		if (res == 0) {
			File file = new File(getVgSignPath(vg));
			return file.lastModified();
		} else {
			return -1L;
		}
	}
	
	private static long checkSignTimeout(String vg) {
		File file = new File(getVgSignPath(vg));
		if (file.exists()) {
			long lastModifiedTime = file.lastModified();
			if ((lastModifiedTime + VG_LOCK_TIMEOUT) <= System.currentTimeMillis()) {
				if (file.lastModified() == lastModifiedTime) {
					file.delete();
				}
			}
			return lastModifiedTime;
		}
		return -1l;
	}
	
	private static String getVgSignPath(String vg){
		return String.format(VG_PATH, vg);

	}
	
	private static void deleteVgSign (String vg, long lastTime) {
		File file = new File(getVgSignPath(vg));
		if (file.exists() && lastTime == file.lastModified()) {
			file.delete();
		}
	}
	
	private static long lockVg(String vg) throws GCloudException {
		boolean isTimeout = false;
		long startTime = System.currentTimeMillis();
		long lastTime = -1l;
		while((lastTime = createVgSign(vg)) < 0 && (!isTimeout)) {
			try {
				Thread.sleep(100L);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			checkSignTimeout(vg);
			
			long nowTime = System.currentTimeMillis();
			isTimeout = (nowTime - startTime) > CHECK_VG_TIMEOUT ? true : false;
			if (isTimeout) {
				log.error("检测vg超时,vg:" + vg);
				throw new GCloudException("::检测vg超时");
			}
		}
		return lastTime;
	}
}
